/**
 * This file is part of Wireless TransFer.
 *
 *   Wireless TransFer is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *	
 *   Wireless TransFer is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Wireless TransFer.  If not, see <http://www.gnu.org/licenses/>.
 *	 
 *	 Copyright (C) 2011
 *   @author christofferP
 */
package com.wirelesstransfer.server.WIFI;

import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.List;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.nio.SelectChannelConnector;

import android.util.Log;

import com.wirelesstransfer.AsyncTasks.UpdateConnectionStatus;

import com.wirelesstransfer.connection.IConnection;
import com.wirelesstransfer.connection.ServerActions;
import com.wirelesstransfer.server.IServer;
import com.wirelesstransfer.server.Ifiles;
import com.wirelesstransfer.server.ServerConnection;
import com.wirelesstransfer.server.ConnectedClients.ConnectedClient;
import com.wirelesstransfer.server.ConnectedClients.ConnectedClientsHandler;
import com.wirelesstransfer.server.WIFI.handlers.ClientActivityHandler;
import com.wirelesstransfer.server.WIFI.handlers.ConnectHandler;
import com.wirelesstransfer.server.WIFI.handlers.DisconnectHandler;
import com.wirelesstransfer.server.WIFI.handlers.ResendFileHandler;
import com.wirelesstransfer.server.WIFI.handlers.SelectFilesHandler;
import com.wirelesstransfer.server.WIFI.handlers.SendFileHandler;
import com.wirelesstransfer.server.authentication.Code;

/**
 * Jettyserver using networkconnection
 * @author christofferP
 *
 */

public final class JettyServer implements IServer {
	
	private String TAG = "JettyServer";
	private Server server;
	private Connector connector;
	private Contexts contexts;
	private HandlerCollection handlers;
	private boolean isRunning;
	
	private final int PORT = 8080;
	
	private IConnection connection;
	private UpdateConnectionStatus updateConnectionStatus;
	
	private static JettyServer instance;
	
	private Ifiles files;
	
	private JettyServer(){
		connector = new SelectChannelConnector();
		contexts = new Contexts();
		initServer();
	}
	
	public static JettyServer getInstance(){
		if (instance == null){
			instance = new JettyServer();
		}
		return instance;
	}
	
	private void initServer(){
		server = new Server();
		server.setConnectors(new Connector[]{connector});
		Log.v(TAG, "server initiated");

	}

	// Easy adding new server handlers
	private void setupHandlers(Ifiles files){
		contexts.add("/" + ServerActions.CONNECT, new ConnectHandler(files));
		contexts.add("/" + ServerActions.SELECTFILES, new SelectFilesHandler(files));
		contexts.add("/" + ServerActions.DISCONNECT, new DisconnectHandler());
		contexts.add("/" + ServerActions.SEND, new SendFileHandler());
		contexts.add("/" + ServerActions.RESEND, new ResendFileHandler());
		contexts.add("/" + ServerActions.CHECKACTIVITY, new ClientActivityHandler());
		
		handlers = new HandlerCollection();
		handlers.setHandlers(new Handler[]{contexts,new DefaultHandler()});
		Log.v(TAG, "added handlers");
	}
	
	private void setupConnection(){
		ServerConnection.setInstance("0.0.0.0", PORT, Code.generateCode());
		//ServerConnection.setInstance(getLocalIpAddress(), PORT, Code.generateCode());
		connection = ServerConnection.getInstance();
	}	

	private void setupConnector(){
		connector.setPort(PORT);
		connector.setHost(connection.getIP());
	}
	
	public boolean startServer(Ifiles files) {
		setupConnection();
		setupConnector();
		setupHandlers(files);
		server.setHandler(handlers);
		
		this.files = files;
		
		try {
			isRunning = true;
			
			updateConnectionStatus = new UpdateConnectionStatus();
			updateConnectionStatus.execute(connection.getIP(), String.valueOf(connection.getCode()));
			
			server.start();
			// Change status to show ip and code.
		
		} catch (Exception e) {
			stopServer();
		}
		Log.v(TAG, "server started with address: " + connection.getIP() + ":" + connection.getPort());
		return true;
	}
	
	public boolean stopServer() {
			try {
				server.getConnectors()[0].stop();
				server.stop();

			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			files.clearFiles();		

			ConnectedClientsHandler cch = ConnectedClientsHandler.getInstance();		
			for(ConnectedClient client : cch.getConnectedClients()){		
				cch.removeClient(client);		
			}

			isRunning = false;		
			instance = null;
			
			UpdateConnectionStatus c = new UpdateConnectionStatus();
			c.execute("N/A", "N/A");
			
			Log.v(TAG, "server stoped");

		return true;
	}

	public boolean isRunning() {
		return isRunning;
	}
	
	public List<File> getFiles(){
		return files.getFiles();
	}
	
	private String getLocalIpAddress() {
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if (!inetAddress.isLoopbackAddress()) {
						return inetAddress.getHostAddress().toString();
					}
				}
			}
		} catch (SocketException ex) {
		}
		return null;
	}
}